/////////////////////////////////////////////////////////////////////////
//
// Amuse Engine - application
// Copyright (c) 2013.  All Rights Reserved
//
// File:		AEOpenGLDevice.cpp
// Author:		Gianluca Belardelli
// Date:		17/10/2013
//
/////////////////////////////////////////////////////////////////////////
#if defined (AE_OPENGL)

#include <AEEngine.h>
#include "graphics/renderer/opengl/AEOpenGLDevice.h"


#if defined (WIN32)

#define GLEW_STATIC
#include <GL/glew.h>
#include <GL/wglew.h>

#include <gl\gl.h>  // Header File For The OpenGL32 Library
#include <gl\glu.h> // Header File For The GLu32 Library

#include "application\win32\AEWin32Window.h"

#define AE_ENGINEDEVICENAME	"Win32 OpenGL"

AERESULT _initOpenGLWin32( AEVideoConfig *lpConfig );

#define INITOPENGL(cfg) _initOpenGLWin32(cfg)

#elif defined (AE_MACOSX86)

#define AE_ENGINEDEVICENAME	"MacOS X86 OpenGL"
#define GLEW_STATIC
#include <GL/glew.h>
//#include <GL/glxew.h>

AERESULT _initOpenGLMac( AEVideoConfig *lpConfig );

#define INITOPENGL(cfg) _initOpenGLMac(cfg)

#else
#error "AEOpenGLDevice.cpp Piattaforma non specificata!"
#endif

AEOpenGLDevice::AEOpenGLDevice( void )
{
}

AERESULT AEOpenGLDevice::InitVideoDevice( AEVideoConfig *lpConfig )
{
	return INITOPENGL(lpConfig);
}

bool AEOpenGLDevice::SetMode( AEVideoConfig &vcMode )
{
	return true;
}

bool AEOpenGLDevice::IsInitialized( void ) const
{
	return false;
}

void AEOpenGLDevice::UpdateScreen( void )
{
}

bool AEOpenGLDevice::QuerySupportedResolution( AEVideoMode **lpVideoMode, AEUINT32 uiSize )
{
	return true;
}

bool AEOpenGLDevice::ChangeScreenResolution( AEINT32 nNewSizeX, AEINT32 nNewSizeY, AEUINT32 uiRefreshRate )
{
	return true;
}


float AEOpenGLDevice::GetDeviceDpi( void ) const
{
	return 96.0f;
}

char *AEOpenGLDevice::GetNameForEngine( void )
{
	return AE_ENGINEDEVICENAME;
}

#ifdef WIN32

////////////////////////////////////////////////////////////////////////////
//
// Inizio codice specifico per Win32
//
////////////////////////////////////////////////////////////////////////////
AERESULT _initOpenGLWin32( AEVideoConfig *lpConfig )
{
	GLuint glPixelFormat;

	static	PIXELFORMATDESCRIPTOR pfd=				// pfd Tells Windows How We Want Things To Be
	{
		sizeof(PIXELFORMATDESCRIPTOR),				// Size Of This Pixel Format Descriptor
		1,											// Version Number
		PFD_DRAW_TO_WINDOW |						// Format Must Support Window
		PFD_SUPPORT_OPENGL |						// Format Must Support OpenGL
		PFD_DOUBLEBUFFER,							// Must Support Double Buffering
		PFD_TYPE_RGBA,								// Request An RGBA Format
		lpConfig->m_nFBColorBits,					// Select Our Color Depth
		0, 0, 0, 0, 0, 0,							// Color Bits Ignored
		0,											// No Alpha Buffer
		0,											// Shift Bit Ignored
		0,											// No Accumulation Buffer
		0, 0, 0, 0,									// Accumulation Bits Ignored
		16,											// 16Bit Z-Buffer (Depth Buffer)  
		(lpConfig->m_bUseStencilBuffer ? lpConfig->m_nFBDepthStencilBits : 0), // Stencil Buffer
		0,											// No Auxiliary Buffer
		PFD_MAIN_PLANE,								// Main Drawing Layer
		0,											// Reserved
		0, 0, 0										// Layer Masks Ignored
	};

	AEPlatformConfig *lpVideoInfo = lpConfig->GetVideoInfo();
	HDC hDC = ((AEWin32Window *)(lpVideoInfo->lpWindow))->GetHDC();

	int nGLAttributes[] = 
	{
		WGL_DRAW_TO_WINDOW_ARB, GL_TRUE,
        WGL_SUPPORT_OPENGL_ARB, GL_TRUE,
        WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB,
        WGL_COLOR_BITS_ARB, lpConfig->m_nFBColorBits,
        WGL_ALPHA_BITS_ARB, 8,
        WGL_DEPTH_BITS_ARB, 16,
        WGL_STENCIL_BITS_ARB, (lpConfig->m_bUseStencilBuffer ? lpConfig->m_nFBDepthStencilBits : 0),
        WGL_DOUBLE_BUFFER_ARB,GL_TRUE,
        WGL_SAMPLE_BUFFERS_ARB,GL_TRUE,
		WGL_SWAP_METHOD_ARB, WGL_SWAP_EXCHANGE_ARB,
        WGL_SAMPLES_ARB, 4 ,                        // Check For 4x Multisampling
        0,0};	

	float fAttributes[] = {0,0};
	UINT numFormats;


	if( !SetPixelFormat( hDC, 1, &pfd ) )
		return 2;

	lpVideoInfo->hRC = wglCreateContext( hDC );
	if( !lpVideoInfo->hRC )
		return 3;

	if( !wglMakeCurrent( hDC,lpVideoInfo->hRC ) )
		return 4;

	glewInit();

	// Controllo lo estensioni GL minime
	if( !GLEW_ARB_vertex_buffer_object || !GLEW_ARB_fragment_program || !GLEW_ARB_fragment_shader )
		return 22;

	PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB =
        (PFNWGLCHOOSEPIXELFORMATARBPROC)wglGetProcAddress("wglChoosePixelFormatARB");

	if( wglChoosePixelFormatARB != NULL )
	{
		bool bRes = wglChoosePixelFormatARB( hDC, nGLAttributes, fAttributes, 1, (int *)&glPixelFormat, &numFormats );
		if( !bRes )
			return 6;
	}
	else
		return 5;
		
	if( !glPixelFormat )
		return 1;

	if( !SetPixelFormat( hDC, glPixelFormat, &pfd ) )
	{
		DWORD err=GetLastError();
		return 2;
	}
	const char *lpGLVersion = (const char *) glGetString( GL_VERSION );
	const char *lpGLVendor = (const char *) glGetString( GL_VENDOR );
	const char *lpGLRenderer = (const char *) glGetString( GL_RENDERER );
	const char *lpGLExtensions = (const char *) glGetString( GL_EXTENSIONS );
	const char *lpShaders = (const char *)glGetString(GL_SHADING_LANGUAGE_VERSION);

	// Versione minima OpenGL 2.0
	// Shader
	// The version is formatted as <version number><space><vendor-specific information>, where <version number> is a MAJOR.MINOR format, with an optional release number.
	// Until version 3.30, the GLSL version number and the corresponding OpenGL version number were different. Here's a table:
	//	OpenGL
	//	Version 	GLSL
	//	Version
	//	2.0 	1.10
	//	2.1 	1.20
	//	3.0 	1.30
	//	3.1 	1.40
	//	3.2 	1.50
	//	For all versions of OpenGL 3.3 and above, the corresponding GLSL version matches the OpenGL version. So GL 4.1 uses GLSL 4.10.
	//	Direct3D Shader Model 4.0 is equivalent to GLSL version 3.30. Earlier GLSL versions for OpenGL 3.x provide subsets of this functionality, based on the available functionality in the OpenGL version, though 1.50 is almost feature-identical to SM4.
	//	Direct3D Shader Model 5.0 is equivalent to GLSL version 4.30.

	// Estensioni 
	// GL_ARB_vertex_buffer_object = MUST
	// GL_NV_draw_texture = MANDATORY ( dovrebbe servire per gli sprite )
	// GL_ARB_fragment_program = MUST (Shader Model 2)
	// GL_ARB_fragment_shader = MUST (Shader Model 2)
	// If a card supports GL_NV_vertex_program3 or GL_ATI_shader_texture_lod it it supports Shader Model 3.0.
	// If a card supports GL_EXT_gpu_shader4 it is a Shader Model 4.0 card. (Geometry shaders are implemented in GL_EXT_geometry_shader4)

	/*
	CreateVertexBuffer -> glGenBuffers
	CreateIndexBuffer -> glGenBuffers

	SetStreamSource -> glBindBuffer( GL_ARRAY_BUFFER, ...
	SetIndices -> glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, ...
	SetFVF -> gl*Pointer + glEnableClientState
	DrawIndexedPrimitive-> glDrawElements
	*/
	return 0;
}

////////////////////////////////////////////////////////////////////////////
//
// Fine codice specifico per Win32
//
////////////////////////////////////////////////////////////////////////////

#else

////////////////////////////////////////////////////////////////////////////
//
// Inizio codice specifico per MacOS
//
////////////////////////////////////////////////////////////////////////////

AERESULT _initOpenGLMac( AEVideoConfig *lpConfig )
{
	/*
		NOTE: In Mac OS 10.4.3 and later, all GPUs report support for 
		GL_ARB_fragment_shader and GL_ARB_vertex_shader even if they 
		do not support this extension in hardware. To determine if these 
		extensions are hardware accelerated, 
		call CGLGetParameter(kCGLCPGPUFragmentProcessing) and 
		CGLGetParameter(kCGLCPGPUVertexProcessing), repsectively.
	*/
    
    return 0;
}

////////////////////////////////////////////////////////////////////////////
//
// Fine codice specifico per MacOS
//
////////////////////////////////////////////////////////////////////////////

#endif

#endif
